package frame.options.physicalNetworks;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import jxl.LabelCell;
import jxl.NumberCell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import model.components.links.link.PhysicalLink;
import model.components.networks.network.PhysicalNetwork;
import model.components.nodes.node.PhysicalNode;
import model.components.nodes.node.Node;
import model.components.nodes.node.PhysicalRouter;
import model.components.nodes.node.PhysicalServer;
import model.components.nodes.node.PhysicalSwitch;
import frame.MopraFrame;
import frame.networks.tables.PhysicalNetworksTableModel;

@SuppressWarnings("serial")
public class OpenPhysicalNetworksMenuItem extends JMenuItem implements ActionListener
{
	private MopraFrame mopraFrame;
	public MopraFrame getFrame(){ return mopraFrame; }
	public void setFrame( MopraFrame mopraFrame ){ this.mopraFrame = mopraFrame; }

	private JFileChooser fileChooser;
	public JFileChooser getFileChooser(){ return fileChooser; }
    public void setFileChooser( JFileChooser fileChooser ){ this.fileChooser = fileChooser; }
	
	public OpenPhysicalNetworksMenuItem( MopraFrame mopraFrame )
	{
		this.setFrame( mopraFrame );
		
		this.setText( "Open" );
		this.setMnemonic( KeyEvent.VK_O );
		this.setIcon( new ImageIcon( this.getClass().getResource( "/icons/open.png" ) ) );
		this.setFileChooser( new JFileChooser() );
		this.addActionListener( this );
	}
	
	@Override
	public void actionPerformed( ActionEvent actionEvent )
	{
		this.getFrame().getNetworksPanel().getNetworksTablesTabbedPane().setSelectedIndex( 0 );
		
		if( this.getFileChooser().showOpenDialog( this ) == JFileChooser.APPROVE_OPTION )
		{
			try
			{
				List< PhysicalNetwork > physicalNetworks = this.openPhysicalNetworks( this.getFileChooser().getSelectedFile() );
			
				this.getFrame().getSimulator().getPhysicalNetworks().clear();
				this.getFrame().getNetworksPanel().getPhysicalNetworksVisualizationViewersTabbedPane().removeAll();
				this.getFrame().getNetworksPanel().getNetworksTablesTabbedPane().getPhysicalNetworksTable().removeAll();
				
				for( PhysicalNetwork physicalNetwork: physicalNetworks )
				{
					this.getFrame().getSimulator().getPhysicalNetworks().add( physicalNetwork );
					this.getFrame().getNetworksPanel().getPhysicalNetworksVisualizationViewersTabbedPane().addPhysicalNetworkTab( physicalNetwork );
					( (PhysicalNetworksTableModel) getFrame().getNetworksPanel().getNetworksTablesTabbedPane().getPhysicalNetworksTable().getModel() ).addRow( new Object[]{ physicalNetwork.getName(), physicalNetwork.getState() } );
				}
				
				( (PhysicalNetworksTableModel) getFrame().getNetworksPanel().getNetworksTablesTabbedPane().getPhysicalNetworksTable().getModel() ).refresh();
			}
			catch( Exception exception )
			{
				JOptionPane.showMessageDialog( this.getFrame().getNetworksPanel(), "Incorrect file", "Filer error", 1 );
			}
		}
	}
	
	public List< PhysicalNetwork > openPhysicalNetworks( File file ) throws Exception
	{
		List< PhysicalNetwork > physicalNetworks = new ArrayList< PhysicalNetwork >();
		
		Workbook workbook = Workbook.getWorkbook( file );
		
		WritableFont writableFontBold = new WritableFont( WritableFont.ARIAL, 10, WritableFont.BOLD );
		WritableCellFormat writableCellFormatBold = new WritableCellFormat( writableFontBold );
		writableCellFormatBold.setWrap( true );
							
		WritableFont writableFontNoBold = new WritableFont( WritableFont.ARIAL, 10, WritableFont.NO_BOLD );
		WritableCellFormat writableCellFormatNoBold = new WritableCellFormat( writableFontNoBold );
		writableCellFormatNoBold.setWrap( true );
		
		String sheetNames[] = workbook.getSheetNames();
		int sheetCount = 0;
		
		while( sheetCount < sheetNames.length )
		{
			Sheet sheet = workbook.getSheet( sheetNames[ sheetCount++ ] );
			
			int columnCount = 0;
			int rowCount = 2;
			
			String namePrefix = sheet.getCell( columnCount++, rowCount ).getContents();
			int networkNumber = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
			int cpuUnitPrice = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
			int memoryUnitPrice = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
			int diskSpaceUnitPrice = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
			int bandwidthUnitPrice = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
			PhysicalNetwork physicalNetwork = new PhysicalNetwork( namePrefix, networkNumber, cpuUnitPrice, memoryUnitPrice, diskSpaceUnitPrice, bandwidthUnitPrice );
			
			List< Node > nodes = new ArrayList< Node >();
			
			columnCount = 0;	
			rowCount = 5;
			
			while( !sheet.getCell( columnCount, rowCount ).getContents().equals( "LINKS" ) )
			{
				String nameNetwork = ( (LabelCell) sheet.getCell( columnCount++, rowCount ) ).getString();
				int number = (int) ( (NumberCell) sheet.getCell( columnCount++, rowCount ) ).getValue();
				String type = ( (LabelCell) sheet.getCell( columnCount++, rowCount ) ).getString();
				String operatingSystem = ( (LabelCell) sheet.getCell( columnCount++, rowCount ) ).getString();
				String virtualEnvironment = ( (LabelCell) sheet.getCell( columnCount++, rowCount ) ).getString();
				int cpu = (int) ( (NumberCell) sheet.getCell( columnCount++, rowCount ) ).getValue();
				int memory = (int) ( (NumberCell) sheet.getCell( columnCount++, rowCount ) ).getValue();
				int diskSpace  = (int) ( (NumberCell) sheet.getCell( columnCount++, rowCount ) ).getValue();
				int maxVirtualNodesNumber = (int)( (NumberCell) sheet.getCell( columnCount++, rowCount ) ).getValue();
				columnCount = 0;
				rowCount++;
									
				PhysicalNode physicalNode = null;
				
				if( type.equals( Node.ROUTER_TYPE ) )
					physicalNode = new PhysicalRouter( nameNetwork, number, operatingSystem, virtualEnvironment, cpu, memory, maxVirtualNodesNumber );
				
				else if( type.equals( Node.SWITCH_TYPE ) )
					physicalNode = new PhysicalSwitch( nameNetwork, number, operatingSystem, virtualEnvironment, cpu, memory, maxVirtualNodesNumber );
				
				else if( type.equals( Node.SERVER_TYPE ) )
					physicalNode = new PhysicalServer( nameNetwork, number, operatingSystem, virtualEnvironment, cpu, memory, diskSpace, maxVirtualNodesNumber );
				
				physicalNode.setInitialNumber( number );
				nodes.add( physicalNode );
			}
			
			columnCount = 0;
			rowCount += 2;
			
			while( !sheet.getCell( columnCount, rowCount ).getContents().equals( "END" ) )
			{
				String networkName = sheet.getCell( columnCount++, rowCount ).getContents();
				int number = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
				String firstNodeName = sheet.getCell( columnCount++, rowCount ).getContents();
				String secondNodeName = sheet.getCell( columnCount++, rowCount ).getContents();
				int bandwidth = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
				int distance = Integer.parseInt( sheet.getCell( columnCount++, rowCount ).getContents() );
				columnCount = 0;
				rowCount++;
				
				PhysicalLink physicalLink = new PhysicalLink( networkName, number, bandwidth, distance );
				Node firstNode = this.getNodeByName( firstNodeName, nodes );
				Node secondNode = this.getNodeByName( secondNodeName, nodes );
				
				physicalLink.setInitialNumber( number );
				physicalLink.setDistance( distance );
				physicalNetwork.addLinkAndNodes( physicalLink, firstNode, secondNode );
			}
			
			physicalNetworks.add( physicalNetwork );
		}
		
		workbook.close();
		
		return physicalNetworks;
	}
	
	private Node getNodeByName( String nodeName, List< Node > nodes )
	{
		for( Node node: nodes )
			if( node.getName().equals( nodeName ) )
				return node;
		
		return null;
	}

}
